<?php

namespace app\api\controller;

use Throwable;
use think\facade\Config;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Event;
use app\common\controller\Frontend;
use app\common\model\User;
use EasyWeChat\OfficialAccount\Application as OfficialAccount;
use EasyWeChat\OpenPlatform\Application as OpenPlatform;

/**
 * 微信登录控制器
 * 专注于微信登录功能，提供二维码登录和网页授权登录
 */
class Wechat extends Frontend
{
    // ==================== 微信登录配置常量 ====================

    // 缓存键前缀
    private const WECHAT_CACHE_PREFIX = 'wechat_temp_login_';      // 临时登录凭证缓存前缀
    private const WECHAT_QR_CACHE_PREFIX = 'wechat_qr_login_';    // 二维码登录状态缓存前缀

    // 默认参数
    private const WECHAT_STATE_DEFAULT = 'web_auth';              // 默认授权状态参数

    // 过期时间（秒）
    private const TEMP_TOKEN_EXPIRE = 300;                       // 临时凭证有效期：5分钟
    private const QR_CODE_EXPIRE = 600;                          // 二维码有效期：10分钟

    // 默认URL路径
    private const DEFAULT_CALLBACK_PATH = '/api/wechat/webAuth';  // 默认微信授权回调地址
    private const DEFAULT_LOGIN_PATH = '/login';                 // 默认登录页面地址
    private const DEFAULT_SUCCESS_PATH = '/index';               // 默认登录成功跳转地址

    // ==================== 微信登录配置常量结束 ===================

    protected array $noNeedLogin = ['*'];
    protected array $noNeedPermission = ['*'];

    private $officialAccount;
    private $openPlatform;

    public function initialize(): void
    {
        parent::initialize();

        // 初始化微信配置
        $this->initWechatConfig();
    }

    /**
     * 初始化微信配置
     */
    private function initWechatConfig(): void
    {
        $config = [
            'app_id' => Config::get('wechat.official_account.app_id'),
            'secret' => Config::get('wechat.official_account.secret'),
            'token' => Config::get('wechat.official_account.token'),
            'aes_key' => Config::get('wechat.official_account.aes_key'),
            'response_type' => 'array',
            'log' => [
                'level' => 'debug',
                'file' => runtime_path() . 'wechat.log',
            ],
        ];

        $this->officialAccount = new OfficialAccount($config);

        // 如果有开放平台配置，也初始化
        if (Config::get('wechat.open_platform.app_id')) {
            $openConfig = [
                'app_id' => Config::get('wechat.open_platform.app_id'),
                'secret' => Config::get('wechat.open_platform.secret'),
                'token' => Config::get('wechat.open_platform.token'),
                'aes_key' => Config::get('wechat.open_platform.aes_key'),
            ];
            $this->openPlatform = new OpenPlatform($openConfig);
        }
    }

    /**
     * 获取微信登录二维码
     */
    public function getQrCode(): void
    {
        try {
            $scene = $this->request->param('scene', '');
            $expireSeconds = $this->request->param('expire_seconds', self::QR_CODE_EXPIRE);

            if (empty($scene)) {
                $this->error('场景值不能为空');
                return;
            }

            // 生成临时二维码
            $qrcode = $this->officialAccount->qrcode;
            $result = $qrcode->temporary($scene, $expireSeconds);

            if (isset($result['ticket'])) {
                $qrUrl = $qrcode->url($result['ticket']);
                
                // 记录二维码生成日志
                $this->logWechatAction('qr_generate', [
                    'scene' => $scene,
                    'expire_seconds' => $expireSeconds,
                    'ticket' => $result['ticket']
                ]);

                $this->success('获取二维码成功', [
                    'qr_url' => $qrUrl,
                    'ticket' => $result['ticket'],
                    'expire_seconds' => $expireSeconds
                ]);
            } else {
                $this->error('获取二维码失败：微信接口返回异常');
            }
        } catch (Throwable $e) {
            $this->logWechatAction('qr_generate_error', ['error' => $e->getMessage()]);
            $this->error('获取二维码失败: ' . $e->getMessage());
        }
    }

    /**
     * 获取微信授权URL - 简化版
     */
    public function getAuthUrl(): void
    {
        try {
            $state = $this->request->param('state', self::WECHAT_STATE_DEFAULT);
            $redirectUrl = $this->request->param('redirect_url', '');
            
            if (empty($redirectUrl)) {
                $redirectUrl = $this->buildDefaultCallbackUrl();
            }

            $oauth = $this->officialAccount->oauth;
            $authUrl = $oauth->scopes(['snsapi_userinfo'])->redirect($redirectUrl, $state);

            $this->logWechatAction('auth_url_generate', [
                'redirect_url' => $redirectUrl,
                'state' => $state
            ]);

            $this->success('获取授权URL成功', [
                'auth_url' => $authUrl,
                'redirect_url' => $redirectUrl,
                'state' => $state,
                'scope' => 'snsapi_userinfo'
            ]);
        } catch (Throwable $e) {
            $this->logWechatAction('auth_url_error', ['error' => $e->getMessage()]);
            $this->error('获取授权URL失败: ' . $e->getMessage());
        }
    }

    /**
     * 构建默认回调URL
     */
    private function buildDefaultCallbackUrl(): string
    {
        $protocol = $this->request->scheme();
        $host = $this->request->host();
        return $protocol . '://' . $host . self::DEFAULT_CALLBACK_PATH;
    }

    /**
     * 微信网页授权登录
     */
    public function webAuth(): void
    {
        try {
            $code = $this->request->param('code', '');
            $state = $this->request->param('state', '');

            if (!$code) {
                // 如果没有code，可能是用户拒绝授权或其他错误
                $error = $this->request->param('error', '');
                $errorDescription = $this->request->param('error_description', '');

                $this->logWechatAction('auth_error', [
                    'error' => $error,
                    'error_description' => $errorDescription
                ]);

                if ($error) {
                    $this->redirectToLoginPage('授权失败: ' . $errorDescription);
                    return;
                }

                $this->redirectToLoginPage('授权码不能为空');
                return;
            }

            // 通过code获取access_token和用户信息
            $oauth = $this->officialAccount->oauth;

            try {
                $user = $oauth->user();
                $userInfo = $user->toArray();
            } catch (Throwable $e) {
                $this->logWechatAction('get_user_info_error', ['error' => $e->getMessage()]);
                $this->redirectToLoginPage('获取用户信息失败: ' . $e->getMessage());
                return;
            }

            if (!$userInfo || !isset($userInfo['openid'])) {
                $this->logWechatAction('user_info_invalid', ['user_info' => $userInfo]);
                $this->redirectToLoginPage('获取用户信息失败');
                return;
            }

            // 转换用户信息格式
            $wechatUserInfo = [
                'openid' => $userInfo['openid'],
                'unionid' => $userInfo['unionid'] ?? '',
                'nickname' => $userInfo['nickname'] ?? '',
                'avatar' => $userInfo['headimgurl'] ?? '',
                'sex' => $userInfo['sex'] ?? 0,
                'city' => $userInfo['city'] ?? '',
                'province' => $userInfo['province'] ?? '',
                'country' => $userInfo['country'] ?? '',
            ];

            // 处理用户登录
            $result = $this->handleWechatLogin($wechatUserInfo);

            if ($result['success']) {
                // 记录网页授权登录日志
                $this->recordWechatLoginLog($wechatUserInfo, 'success', '', 'web_auth');

                // 生成临时登录凭证
                $tempToken = $this->generateTempLoginToken($result['user_info']['id']);

                // 重定向到登录页面，携带临时凭证
                $loginUrl = self::DEFAULT_LOGIN_PATH;
                $separator = strpos($loginUrl, '?') !== false ? '&' : '?';
                $finalUrl = $loginUrl . $separator . 'wechat_login_token=' . $tempToken;

                header('Location: ' . $finalUrl);
                exit;
            } else {
                $this->recordWechatLoginLog($wechatUserInfo, 'failed', $result['message'], 'web_auth');
                $this->redirectToLoginPage('登录失败: ' . $result['message']);
            }
        } catch (Throwable $e) {
            $this->logWechatAction('web_auth_error', ['error' => $e->getMessage()]);
            $this->redirectToLoginPage('微信授权失败: ' . $e->getMessage());
        }
    }

    /**
     * 重定向到登录页面（带错误信息）
     */
    private function redirectToLoginPage(string $error = ''): void
    {
        $loginUrl = self::DEFAULT_LOGIN_PATH;

        if ($error) {
            $separator = strpos($loginUrl, '?') !== false ? '&' : '?';
            $loginUrl .= $separator . 'error=' . urlencode($error);
        }

        header('Location: ' . $loginUrl);
        exit;
    }

    /**
     * 获取微信用户信息
     */
    private function getWechatUserInfo(string $openid): ?array
    {
        try {
            $user = $this->officialAccount->user;
            $userInfo = $user->get($openid);

            if (!$userInfo || !isset($userInfo['openid'])) {
                return null;
            }

            return [
                'openid' => $openid,
                'unionid' => $userInfo['unionid'] ?? '',
                'nickname' => $userInfo['nickname'] ?? '',
                'avatar' => $userInfo['headimgurl'] ?? '',
                'sex' => $userInfo['sex'] ?? 0,
                'city' => $userInfo['city'] ?? '',
                'province' => $userInfo['province'] ?? '',
                'country' => $userInfo['country'] ?? '',
            ];
        } catch (Throwable $e) {
            $this->logWechatAction('get_user_info_error', [
                'openid' => $openid,
                'error' => $e->getMessage()
            ]);
            return null;
        }
    }

    /**
     * 处理微信登录
     */
    private function handleWechatLogin(array $wechatUserInfo): array
    {
        try {
            $openid = $wechatUserInfo['openid'];
            $unionid = $wechatUserInfo['unionid'];

            // 查找是否已有用户
            $user = null;
            if ($unionid) {
                $user = User::where('wechat_unionid', $unionid)->find();
            }
            if (!$user && $openid) {
                $user = User::where('wechat_openid', $openid)->find();
            }

            if (!$user) {
                // 创建新用户
                $user = $this->createWechatUser($wechatUserInfo);
                if (!$user) {
                    return ['success' => false, 'message' => '创建用户失败'];
                }
            } else {
                // 更新用户信息
                $this->updateWechatUser($user, $wechatUserInfo);
            }

            // 执行登录
            $loginResult = $this->performWechatLogin($user);

            if (!$loginResult) {
                return ['success' => false, 'message' => '登录失败'];
            }

            // 记录登录日志
            $this->recordWechatLoginLog($wechatUserInfo, 'success');

            return [
                'success' => true,
                'token' => $this->auth->getToken(),
                'user_info' => $this->auth->getUserInfo()
            ];
        } catch (Throwable $e) {
            $this->recordWechatLoginLog($wechatUserInfo, 'failed', $e->getMessage());
            return ['success' => false, 'message' => $e->getMessage()];
        }
    }

    /**
     * 创建微信用户
     */
    private function createWechatUser(array $wechatUserInfo): ?User
    {
        Db::startTrans();
        try {
            $ip = $this->request->ip();
            $time = time();

            // 生成唯一用户名
            $username = $this->generateUniqueUsername($wechatUserInfo['openid']);

            $userData = [
                'username' => $username,
                'nickname' => $wechatUserInfo['nickname'] ?: $username,
                'avatar' => $wechatUserInfo['avatar'],
                'password' => '', // 微信登录不需要密码
                'salt' => '',
                'email' => '',
                'mobile' => '',
                'wechat_openid' => $wechatUserInfo['openid'],
                'wechat_unionid' => $wechatUserInfo['unionid'],
                'wechat_nickname' => $wechatUserInfo['nickname'],
                'wechat_avatar' => $wechatUserInfo['avatar'],
                'login_type' => 'wechat',
                'group_id' => 1, // 默认分组
                'status' => 'enable',
                'join_ip' => $ip,
                'join_time' => $time,
                'last_login_ip' => $ip,
                'last_login_time' => $time,
                'create_time' => $time,
                'update_time' => $time,
            ];

            $user = User::create($userData);

            Db::commit();

            // 触发用户注册成功事件
            Event::trigger('userRegisterSuccess', $user);

            $this->logWechatAction('user_created', [
                'user_id' => $user->id,
                'username' => $username,
                'openid' => $wechatUserInfo['openid']
            ]);

            return $user;
        } catch (Throwable $e) {
            Db::rollback();
            $this->logWechatAction('user_create_error', [
                'error' => $e->getMessage(),
                'openid' => $wechatUserInfo['openid']
            ]);
            return null;
        }
    }

    /**
     * 生成唯一用户名
     */
    private function generateUniqueUsername(string $openid): string
    {
        $baseUsername = 'wx_' . substr($openid, -8);
        $username = $baseUsername;
        $suffix = 1;

        while (User::where('username', $username)->count() > 0) {
            $username = $baseUsername . '_' . $suffix;
            $suffix++;
        }

        return $username;
    }

    /**
     * 更新微信用户信息
     */
    private function updateWechatUser(User $user, array $wechatUserInfo): void
    {
        $user->wechat_nickname = $wechatUserInfo['nickname'];
        $user->wechat_avatar = $wechatUserInfo['avatar'];
        // 只有用户昵称为空时才更新
        if (empty($user->nickname)) {
            $user->nickname = $wechatUserInfo['nickname'];
        }
        // 只有用户头像为空时才更新
        if (empty($user->avatar)) {
            $user->avatar = $wechatUserInfo['avatar'];
        }
        $user->last_login_ip = $this->request->ip();
        $user->last_login_time = time();
        $user->update_time = time();
        $user->save();

        $this->logWechatAction('user_updated', [
            'user_id' => $user->id,
            'openid' => $wechatUserInfo['openid']
        ]);
    }

    /**
     * 执行微信登录
     */
    private function performWechatLogin(User $user): bool
    {
        try {
            // 使用原系统的直接登录方法
            return $this->auth->direct($user->id);
        } catch (Throwable $e) {
            $this->logWechatAction('login_error', [
                'user_id' => $user->id,
                'error' => $e->getMessage()
            ]);
            return false;
        }
    }

    /**
     * 记录微信登录日志
     */
    private function recordWechatLoginLog(array $wechatUserInfo, string $status, string $errorMsg = '', string $loginType = 'qr_code'): void
    {
        try {
            $log = [
                'openid' => $wechatUserInfo['openid'],
                'unionid' => $wechatUserInfo['unionid'],
                'nickname' => $wechatUserInfo['nickname'],
                'avatar' => $wechatUserInfo['avatar'],
                'login_ip' => $this->request->ip(),
                'user_agent' => $this->request->header('user-agent'),
                'status' => $status,
                'error_msg' => $errorMsg,
                'login_type' => $loginType,
                'create_time' => time(),
            ];

            // 记录到日志文件
            \think\facade\Log::info('微信登录日志', $log);

            // 如果有ba_wechat_login_log表，也可以记录到数据库
            try {
                Db::table('ba_wechat_login_log')->insert(array_merge($log, [
                    'user_id' => $this->auth->isLogin() ? $this->auth->id : null,
                    'login_type' => $loginType
                ]));
            } catch (Throwable $e) {
                // 数据库记录失败不影响主流程
            }
        } catch (Throwable $e) {
            // 记录日志失败不影响主流程
        }
    }

    /**
     * 通用微信操作日志记录
     */
    private function logWechatAction(string $action, array $data = []): void
    {
        try {
            $logData = array_merge([
                'action' => $action,
                'ip' => $this->request->ip(),
                'user_agent' => $this->request->header('user-agent'),
                'timestamp' => time(),
            ], $data);

            \think\facade\Log::info('微信操作日志', $logData);
        } catch (Throwable $e) {
            // 日志记录失败不影响主流程
        }
    }

    /**
     * 通知二维码登录结果
     */
    private function notifyQrLoginResult(string $scene, array $result): void
    {
        // 这里可以通过WebSocket或其他方式通知前端
        // 暂时使用缓存存储结果，前端轮询获取
        $cacheKey = self::WECHAT_QR_CACHE_PREFIX . $scene;
        Cache::set($cacheKey, $result, self::TEMP_TOKEN_EXPIRE);
    }

    /**
     * 检查二维码登录状态
     */
    public function checkQrLogin(): void
    {
        $scene = $this->request->param('scene', '');
        if (!$scene) {
            $this->error('参数错误');
            return;
        }

        $cacheKey = self::WECHAT_QR_CACHE_PREFIX . $scene;
        $result = Cache::get($cacheKey);

        if ($result) {
            Cache::delete($cacheKey); // 获取后删除
            $this->success('获取登录结果成功', $result);
        } else {
            $this->error('登录结果不存在或已过期', [], 0);
        }
    }

    /**
     * 生成临时登录凭证
     */
    private function generateTempLoginToken(int $userId): string
    {
        $tempToken = md5(uniqid() . $userId . time());

        // 将临时凭证存储到缓存中
        cache(self::WECHAT_CACHE_PREFIX . $tempToken, [
            'user_id' => $userId,
            'create_time' => time(),
            'expire_time' => time() + self::TEMP_TOKEN_EXPIRE
        ], self::TEMP_TOKEN_EXPIRE);

        return $tempToken;
    }

    /**
     * 使用临时凭证登录
     */
    public function loginByTempToken(): void
    {
        try {
            $tempToken = $this->request->param('temp_token', '');

            if (!$tempToken) {
                $this->error('临时凭证不能为空');
                return;
            }

            // 从缓存中获取临时凭证信息
            $cacheKey = self::WECHAT_CACHE_PREFIX . $tempToken;
            $tempData = cache($cacheKey);

            if (!$tempData) {
                $this->error('临时凭证无效或已过期');
                return;
            }

            // 检查是否过期
            if (time() > $tempData['expire_time']) {
                cache($cacheKey, null); // 删除过期凭证
                $this->error('临时凭证已过期');
                return;
            }

            // 获取用户信息
            $user = User::find($tempData['user_id']);
            if (!$user) {
                cache($cacheKey, null); // 删除无效凭证
                $this->error('用户不存在');
                return;
            }

            // 执行登录（复用原有登录逻辑）
            $loginResult = $this->performWechatLogin($user);

            if ($loginResult) {
                // 登录成功，删除临时凭证
                cache($cacheKey, null);

                $this->logWechatAction('temp_token_login_success', [
                    'user_id' => $user->id,
                    'temp_token' => substr($tempToken, 0, 8) . '...'
                ]);

                $this->success('登录成功', [
                    'token' => $this->auth->getToken(),
                    'user_info' => $this->auth->getUserInfo()
                ]);
            } else {
                $this->error('登录失败');
            }
        } catch (Throwable $e) {
            $this->logWechatAction('temp_token_login_error', ['error' => $e->getMessage()]);
            $this->error('临时凭证登录失败: ' . $e->getMessage());
        }
    }

    /**
     * 微信消息处理（用于接收扫码事件）
     */
    public function serve(): void
    {
        try {
            $server = $this->officialAccount->server;

            // 监听扫码事件
            $server->push(function ($message) {
                if ($message['MsgType'] === 'event' && $message['Event'] === 'SCAN') {
                    // 处理扫码事件
                    $scene = $message['EventKey'];
                    $openid = $message['FromUserName'];

                    $this->logWechatAction('qr_scan', [
                        'scene' => $scene,
                        'openid' => $openid
                    ]);

                    // 获取用户信息并处理登录
                    $userInfo = $this->getWechatUserInfo($openid);
                    if ($userInfo) {
                        $result = $this->handleWechatLogin($userInfo);
                        $this->notifyQrLoginResult($scene, $result);
                    }
                }

                return 'success';
            });

            $response = $server->serve();
            $response->send();
        } catch (Throwable $e) {
            $this->logWechatAction('serve_error', ['error' => $e->getMessage()]);
            $this->error('处理微信消息失败: ' . $e->getMessage());
        }
    }
}
